#include <hgCommon.h>
#include <fstream>
#include <ctime>

using namespace hg;

HM_SingleOut(Common);
HM_SingleOut(Saver);

_TypeWarehouse* _TypeWarehouse::getInstance()
{
	static _TypeWarehouse obj;
	return &obj;
}


void Common::log(const String& str)
{
	std::ofstream f;
	f.open("hg.log", std::ios::app);
	if (f.is_open())
	{
		f << str << "\n";
		f.close();
	}
	puts(str.data());

#ifdef WIN32
	OutputDebugString(str.data());
#endif
}




void _TypeWarehouse::regCreateFunc(size_t hashCode, std::function<void*()> func)
{
	if (func == nullptr) return;
	mCreateListMap[hashCode] = func;
}

void* _TypeWarehouse::CreateObject(size_t hashCode)
{
	auto it = mCreateListMap.find(hashCode);
	if (it == mCreateListMap.end()) return nullptr;
	return it->second();
}

bool _TypeWarehouse::CheckObject(size_t hashCode)
{
	auto it = mCreateListMap.find(hashCode);
	if (it == mCreateListMap.end()) return false;
	return true;
}

StoredObject::StoredObject() :pOut(nullptr), pIn(nullptr){}
inline void StoredObject::save(std::ostream* os) { pOut = os; triggerSave(); pOut = nullptr; }
inline void StoredObject::load(std::istream* is) { pIn = is; triggerLoad(); pIn = nullptr; }
void StoredObject::saveAttribute(const String& value){
	size_t sz = (value.length() + 1);
	pOut->write((char*)&sz, sizeof(size_t));
	pOut->write(value.data(), sz);
}
void StoredObject::saveAttributeType(StoredObject* target)
{
	size_t hash = typeid(*target).hash_code();
	if (!HM_TypeCheck(hash)){ saveAttribute(0); return; }
	saveAttribute(hash);
	target->save(pOut);
}
void StoredObject::loadAttribute(String& value)
{
	size_t sz = 0;
	pIn->read((char*)&sz, sizeof(size_t));
	char* buffer = new char[sz];
	pIn->read(buffer, sz);
	value = buffer;
	delete[] buffer;
}





bool Saver::save(const String& path, StoredObject* obj)
{
	std::ofstream file(path.data(), std::ios_base::binary | std::ios_base::out);
	if (!file.is_open()) return false;
	save(&file, obj);
	file.close();
	return true;
}

bool Saver::save(std::ostream* os, StoredObject* obj)
{
	if (!os->good()) return false;
	size_t hash = typeid(*obj).hash_code();
	os->write((char*)&hash, sizeof(size_t));
	obj->save(os);
	return true;
}

StoredObject* Saver::load(const String& path, const size_t& hash)
{
	std::ifstream file;
	file.open(path.data(), std::ios_base::binary | std::ios_base::in);
	if (!file.is_open()) return nullptr;
	StoredObject* obj = load(&file, hash);
	file.close();
	return obj;
}

StoredObject* Saver::load(std::istream* is, const size_t& hash)
{
	if (!is->good()) return nullptr;
	size_t typeHash = 0;
	is->read((char*)&typeHash, sizeof(size_t));
	if (hash != typeHash) return nullptr;
	StoredObject* tObject = (StoredObject*)HM_TypeCreate(typeHash);
	if (tObject != nullptr)
		tObject->load(is);
	return tObject;
}
